﻿//AcademicPlanner - course registration planning web app.
//Copyright (C) 2009  Boubacar Diallo

//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either version 2
//of the License, or (at your option) any later version.

//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.

//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.


using System;
using System.Data;
using NHibernate;
using NHibernate.Cfg;
using AcademicPlanner.Data.Repositories;

namespace AcademicPlanner.Data
{
	/// <summary>
	/// DataSourceAccessSupervisor is the front controller and master object
	/// of the data layer of the AcademicPlanner application.
	/// </summary>
	/// <since>1.0</since>
	public class DataSourceAccessSupervisor
	{
		private ISessionFactory sessions;

		private ISession session;

		private ITransaction currentTransaction;

		private int transactionDepth = 0;


		/// <summary>
		/// Gets the current NHibernate session.
		/// </summary>
		/// <since>1.0</since>
		internal ISession Session { get { return session; } }

		/// <summary>
		/// Gets the current database connection used by the data layer.
		/// </summary>
		/// <since>1.0</since>
		public IDbConnection Connection { get { return session.Connection; } }

		/// <summary>
		/// Gets the repository responsible for <c>PersonEntity</c>s.
		/// </summary>
		/// <since>1.0</since>
		public PersonEntityRepository PersonEntityRepo { get { return PersonEntityRepository.GetInstance(); } }

		/// <summary>
		/// Gets the repository responsible for <c>AccountEntity</c>s.
		/// </summary>
		/// <since>1.0</since>
		public AccountEntityRepository AccountEntityRepo { get { return AccountEntityRepository.GetInstance(); } }

		/// <summary>
		/// Gets the repository responsible for <c>UserEntity</c>s.
		/// </summary>
		/// <since>1.0</since>
		public UserEntityRepository UserEntityRepo { get { return UserEntityRepository.GetInstance(); } }

		/// <summary>
		/// Gets the repository responsible for <c>AcademicPlanEntity</c>s.
		/// </summary>
		/// <since>1.0</since>
		public AcademicPlanEntityRepository AcademicPlanEntityRepo 
		{ 
			get { return AcademicPlanEntityRepository.GetInstance(); } 
		}

		/// <summary>
		/// Gets the repository responsible for <c>PlannerEntity</c>s.
		/// </summary>
		/// <since>1.0</since>
		public PlannerEntityRepository PlannerEntityRepo { get { return PlannerEntityRepository.GetInstance(); } }

		/// <summary>
		/// Gets the repository responsible for <c>CourseCategoryEntity</c>s.
		/// </summary>
		/// <since>1.0</since>
		public CourseCategoryEntityRepository CourseCategoryEntityRepo 
		{ 
			get { return CourseCategoryEntityRepository.GetInstance(); } 
		}

		/// <summary>
		/// Gets the repository responsible for <c>CourseDivisionEntity</c>s.
		/// </summary>
		/// <since>1.0</since>
		public CourseDivisionEntityRepository CourseDivisionEntityRepo 
		{
			get { return CourseDivisionEntityRepository.GetInstance(); }
		}

		/// <summary>
		/// Gets the repository responsible for <c>AcademicTermEntity</c>s.
		/// </summary>
		/// <since>1.0</since>
		public AcademicTermEntityRepository AcademicTermEntityRepo 
		{
			get { return AcademicTermEntityRepository.GetInstance(); } 
		}

		/// <summary>
		/// Gets the repository responsible for <c>ProgramEntity</c>s.
		/// </summary>
		/// <since>1.0</since>
		public ProgramEntityRepository ProgramEntityRepo { get { return ProgramEntityRepository.GetInstance(); } }

		/// <summary>
		/// Gets the repository responsible for <c>RegistrationEntity</c>s.
		/// </summary>
		/// <since>1.0</since>
		public RegistrationEntityRepository RegistrationEntityRepo 
		{ 
			get 
			{ 
				return RegistrationEntityRepository.GetInstance(); 
			} 
		}

		/// <summary>
		/// Gets the repository responsible for <c>CourseEntity</c>s.
		/// </summary>
		/// <since>1.0</since>
		public CourseEntityRepository CourseEntityRepo { get { return CourseEntityRepository.GetInstance(); } }

		/// <summary>
		/// Gets the repository responsible for <c>AcademicScheduleEntity</c>s.
		/// </summary>
		/// <since>1.0</since>
		public AcademicScheduleEntityRepository AcademicScheduleEntityRepo
		{
			get { return AcademicScheduleEntityRepository.GetInstance(); }
		}


		private DataSourceAccessSupervisor() 
		{
			sessions = new Configuration().Configure()
							.SetProperty("hibernate.query.substitutions", "true 1, false 0")
							.BuildSessionFactory();
			NewSession();
		}

		private class InstanceHolder 
		{
			internal static DataSourceAccessSupervisor INSTANCE = new DataSourceAccessSupervisor(); 
		}


		/// <summary>
		/// Gets the single instance of DataSourceAccessSupervisor.
		/// </summary>
		/// <returns>The single instance of DataSourceAccessSupervisor.</returns>
		/// <since>1.0</since>
		public static DataSourceAccessSupervisor GetInstance()
		{ 
			return InstanceHolder.INSTANCE; 
		}


		private void RenewSession()
		{
			session.Close();
			NewSession();
		}

		private void NewSession()
		{
			session = sessions.OpenSession();
			EnableFilters();
		}

		internal void EnableFilters()
		{
			session.EnableFilter("TrashedOrNotFilter").SetParameter("trashedOrNot", false);
		}

		internal void DisableFilters()
		{
			session.DisableFilter("TrashedOrNotFilter");
		}

		/// <summary>
		/// Prepares the persistence for transaction oriented operations.
		/// </summary>
		/// <since>1.0</since>
		public void PrepareForWork()
		{
			StartTransaction();
		}

		/// <summary>
		/// Cleans up the persistence after transaction oriented operations.
		/// Changes are maintained or reverted based on <paramref name="pSucceeded"/>.
		/// </summary>
		/// <param name="pSucceeded">
		/// Whether the transaction oriented operations to clean up after were successful or not.
		/// </param>
		/// <since>1.0</since>
		public void CleanUpAfterWork(bool pSucceeded)
		{
			if (pSucceeded)
				CommitTransaction();
			else
				RollBackTransaction();
		}

		private void StartTransaction()
		{
			if (transactionDepth++ == 0)
				currentTransaction = session.BeginTransaction();
		}

		private void RollBackTransaction()
		{
			if (transactionDepth-- == 1)
			{
				currentTransaction.Rollback();
			}
		}

		private void CommitTransaction()
		{
			if (transactionDepth-- == 1)
			{
				currentTransaction.Commit();
			}
		}

	}
}
